package cn.aresoft.excel.utils;

import cn.aresoft.excel.emuns.ValidateRuleEnumn;
import cn.aresoft.excel.entity.ExcelDictModel;
import cn.aresoft.excel.entity.ExcelFieldEntity;
import cn.aresoft.excel.entity.ExcelVaildateEntity;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author yangfeng
 * @Date 2023/6/16 15:46
 */
public class ExcelValidateFieldUtil {

    /**
     * excel字段基础校验方法
     * @param excelFieldEntity  实体对象EXCEL属性
     * @param fieldValue  校验字段值
     * @param record  实体对象
     * @return
     * @throws Exception
     */
    public static String validateField(ExcelFieldEntity excelFieldEntity, Object fieldValue, Object record) throws Exception {

        ExcelVaildateEntity excelVaildateEntity = excelFieldEntity.getExcelVaildateEntity();
        ValidateRuleEnumn[] validateRuleEnumnArrayList = excelVaildateEntity.getRules();
        StringBuffer validateBuff = new StringBuffer();
        if (fieldValue != null) {
                for (ValidateRuleEnumn validateRuleEnumn : validateRuleEnumnArrayList) {
                    if (validateRuleEnumn.equals(ValidateRuleEnumn.NOT_CONTAIN_ALL_ANGLE_RULE)) {
                        /**全角字符校验*/
                        boolean validateFlag = isFullAngle(fieldValue.toString());
                        if (validateFlag) {
                            validateBuff.append("值不能包含全角字符！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.NOT_CONTAIN_CN_RULE)) {
                        /**包含中文校验*/
                        boolean validateFlag = containCn(fieldValue.toString());
                        if (validateFlag) {
                            validateBuff.append("值不能包含中文！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.DICT_CODE_RULE)) {
                        /**数据字典校验*/
                        if (excelFieldEntity.getExcelDictModelList() != null && !excelFieldEntity.getExcelDictModelList().isEmpty()) {
                            boolean validateFlag = dictCodeInValidate(fieldValue.toString(), excelFieldEntity.getExcelDictModelList());
                            if (validateFlag) {
                                validateBuff.append("字典不符合规范！,");
                            }
                        } else {
                            validateBuff.append("字典不存在，无法进行校验！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.NOT_TRIM_RULE)) {
                        /**前后空格校验*/
                        boolean validateFlag = containEmptyValidate(fieldValue.toString());
                        if (validateFlag) {
                            validateBuff.append("值不能包含前后空格！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.FIELD_LENGTH_LE_RULE)) {
                        /**字符串长度校验*/
                        if (excelVaildateEntity.getLength() != 0) {
                            boolean validateFlag = strLengthValidate(fieldValue.toString(), excelVaildateEntity.getLength(), "le");
                            if (!validateFlag) {
                                validateBuff.append("值长度不得超出限定值" + excelVaildateEntity.getLength() + "！,");
                            }
                        } else {
                            validateBuff.append( "长度限定值未设置，无法进行校验！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.FIELD_LENGTH_EQ_RULE)) {
                        /**字符串长度校验*/
                        if (excelVaildateEntity.getLength() != 0) {
                            boolean validateFlag = strLengthValidate(fieldValue.toString(), excelVaildateEntity.getLength(), "eq");
                            if (!validateFlag) {
                                validateBuff.append("值长度不等于限定值" + excelVaildateEntity.getLength() + "！,");
                            }
                        } else {
                            validateBuff.append("长度限定值未设置，无法进行校验！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.FIELD_LENGTH_GE_RULE)) {
                        /**字符串长度校验*/
                        if (excelVaildateEntity.getLength() != 0) {
                            boolean validateFlag = strLengthValidate(fieldValue.toString(), excelVaildateEntity.getLength(), "ge");
                            if (!validateFlag) {
                                validateBuff.append("值长度不得小于限定值" + excelVaildateEntity.getLength() + "！,");
                            }
                        } else {
                            validateBuff.append("长度限定值未设置，无法进行校验！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.SPECIAIL_CHAR_RULE)) {
                        /**特殊字符校验*/
                        if (excelVaildateEntity.getSpecialChar().length != 0) {
                            boolean validateFlag = containSpecialCharValidate(fieldValue.toString(), excelVaildateEntity.getSpecialChar());
                            if (validateFlag) {
                                validateBuff.append("值不能包含特殊字符" + String.join(",",excelVaildateEntity.getSpecialChar())+ "！,");
                            }
                        } else {
                            validateBuff.append("特殊字符未限定，无法进行校验！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.NOT_EQ_FIX_CONSTANT)) {
                        /**常量字符串校验*/
                        if (StringUtils.isNotEmpty(excelVaildateEntity.getConstantStr())) {
                            boolean validateFlag = fieldValue.toString().equals(excelVaildateEntity.getConstantStr());
                            if (validateFlag) {
                                validateBuff.append("值不能为固定值" + excelVaildateEntity.getConstantStr() + "！,");
                            }
                        } else {
                            validateBuff.append("常量字符未限定，无法进行校验！,");
                        }
                    }else if (validateRuleEnumn.equals(ValidateRuleEnumn.EQ_FIX_CONSTANT)) {
                        /**常量字符串校验*/
                        if (StringUtils.isNotEmpty(excelVaildateEntity.getConstantStr())) {
                            boolean validateFlag = fieldValue.toString().equals(excelVaildateEntity.getConstantStr());
                            if (!validateFlag) {
                                validateBuff.append("值必须为固定值" + excelVaildateEntity.getConstantStr() + "！,");
                            }
                        } else {
                            validateBuff.append("常量字符未限定，无法进行校验！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.CONTAIN_BLANK_RULE)) {
                        /**空格校验*/
                        boolean validateFlag = containBlankValidate(fieldValue.toString());
                        if (validateFlag) {
                            validateBuff.append("值不能包含空格！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.ONLY_NUMBER_RULE)) {
                        /**只允许数字校验*/
                        boolean validateFlag = isNumeric(fieldValue.toString());
                        if (!validateFlag) {
                            validateBuff.append("值仅允许由数值组成！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.NOT_ONLY_NUMBER_RULE)) {
                        /**不允许仅由数值组成校验*/
                        boolean validateFlag = isNumeric(fieldValue.toString());
                        if (validateFlag) {
                            validateBuff.append("值不能仅由数值组成！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.ONLY_NUMBER_REMAIN_OPITON_RULE)) {
                        /**保留小数位*/
                        if (excelVaildateEntity.getLength() != 0) {
                            boolean validateFlag = remainPoint(fieldValue.toString(), excelVaildateEntity.getLength());
                            if (!validateFlag) {
                                validateBuff.append("值只能为数值型，且最多保留：" + excelVaildateEntity.getLength() + "位小数！");
                            }
                        } else {
                            validateBuff.append(" 请设置限定小数点位数！,");
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.DATA_GE_RULE)) {
                        boolean validateFlag = dataCompareByField(excelFieldEntity,fieldValue,excelVaildateEntity.getConstantStr(),"ge");
                        if (!validateFlag) {
                            validateBuff.append("值必须大于等于：" + excelVaildateEntity.getConstantStr());
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.DATA_GT_RULE)) {
                        boolean validateFlag = dataCompareByField(excelFieldEntity,fieldValue,excelVaildateEntity.getConstantStr(),"gt");
                        if (!validateFlag) {
                            validateBuff.append("值必须大于：" + excelVaildateEntity.getConstantStr());
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.DATA_LE_RULE)) {
                        boolean validateFlag = dataCompareByField(excelFieldEntity,fieldValue,excelVaildateEntity.getConstantStr(),"le");
                        if (!validateFlag) {
                            validateBuff.append("值必须小于等于：" + excelVaildateEntity.getConstantStr());
                        }
                    } else if (validateRuleEnumn.equals(ValidateRuleEnumn.DATA_LT_RULE)) {
                        boolean validateFlag = dataCompareByField(excelFieldEntity,fieldValue,excelVaildateEntity.getConstantStr(),"lt");
                        if (!validateFlag) {
                            validateBuff.append("值必须小于：" + excelVaildateEntity.getConstantStr());
                        }
                    }
                }
                /**自定义校验*/
                if (excelVaildateEntity.getFieldValidateHandler() != null) {
                    try {
                        String message = excelVaildateEntity.getFieldValidateHandler().fieldValidate(fieldValue,record,excelFieldEntity);
                        validateBuff.append(message);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
        } else {
            if (Arrays.asList(validateRuleEnumnArrayList).contains(ValidateRuleEnumn.VALUE_EMPTY_RULE)) {
                validateBuff.append("值不能为空");
            }
        }
        return validateBuff.toString();
    }

    /**
     * 大小比较
     * @param excelFieldEntity
     * @param fieldValue
     * @param constantStr
     * @param type
     * @return
     */
    private static boolean dataCompareByField(ExcelFieldEntity excelFieldEntity,Object fieldValue,String constantStr,String type){
        boolean validateFlag = false;
        if(Number.class.isAssignableFrom(excelFieldEntity.getField().getType())){
            BigDecimal baseValue = new BigDecimal(constantStr);
            BigDecimal busiValue = new BigDecimal(fieldValue.toString());
            switch (type) {
                case "gt": validateFlag = busiValue.compareTo(baseValue) > 0 ? true : false;  break;
                case "ge": validateFlag = busiValue.compareTo(baseValue) >= 0 ? true : false; break;
                case "eq": validateFlag = busiValue.compareTo(baseValue) == 0 ? true : false; break;
                case "lt": validateFlag = busiValue.compareTo(baseValue) < 0 ? true : false; break;
                case "le": validateFlag = busiValue.compareTo(baseValue) <= 0 ? true : false; break;
                default:validateFlag = false;break;
            }
        }else if(Date.class.equals(excelFieldEntity.getField().getType())) {
            Date busiValue = (Date)fieldValue;
            Date baseValue = null;
            try {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat(excelFieldEntity.getPattern());
                baseValue = simpleDateFormat.parse(constantStr);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            switch (type) {
                case "gt": validateFlag = busiValue.compareTo(baseValue) > 0 ? true : false;  break;
                case "ge": validateFlag = busiValue.compareTo(baseValue) >= 0 ? true : false; break;
                case "eq": validateFlag = busiValue.compareTo(baseValue) == 0 ? true : false; break;
                case "lt": validateFlag = busiValue.compareTo(baseValue) < 0 ? true : false; break;
                case "le": validateFlag = busiValue.compareTo(baseValue) <= 0 ? true : false; break;
                default:validateFlag = false;break;
            }
        }
        return validateFlag;

    }

    /**
     * 判断字符串是否包含全角字符（排除中文字段）
     *
     * @param str
     * @return
     */
    public static boolean isFullAngle(String str) {
        char[] charsArr = str.toCharArray();
        boolean containFullAngle = false;
        for (int i = 0; i < charsArr.length; i++) {
            String temp = String.valueOf(charsArr[i]);
            // 判断是全角字符,排除中文字符
            if (temp.matches("[^\\x00-\\xff]")) {
                containFullAngle = true;
                break;
            }
        }
        return containFullAngle;
    }

    /**
     * 判断字符串是否包含中文
     *
     * @param str
     * @return
     */
    public static boolean containCn(String str) {
        char[] charsArr = str.toCharArray();
        boolean containCn = false;
        for (int i = 0; i < charsArr.length; i++) {
            String temp = String.valueOf(charsArr[i]);
            //判断是否包含中文字符
            if (temp.matches("[\u4e00-\u9fa5]")) {
                containCn = true;
                break;
            }
        }
        return containCn;
    }

    /**
     * 判断字符串是否包含中文
     *
     * @param value
     * @param validateDictModels
     * @return
     */
    private static boolean dictCodeInValidate(String value, List<ExcelDictModel> validateDictModels) {
        List<String> dictCodeList = validateDictModels.stream().map(ExcelDictModel::getValue).collect(Collectors.toList());
        if (!dictCodeList.isEmpty() && dictCodeList.contains(value)) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 判断字符串是否包含前后空格
     *
     * @param value
     * @return
     */
    public static boolean containEmptyValidate(String value) {
        String trimValue = value.trim();
        if (value.length() != trimValue.length()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断字符串中是否包含空格
     *
     * @param value
     * @return
     */
    public static boolean containBlankValidate(String value) {
        String notBlankValue = value.replaceAll(" ", "");
        if (value.length() != notBlankValue.length()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 特殊字符校验
     *
     * @param value
     * @param specialCharArr
     * @return
     */
    public static boolean containSpecialCharValidate(String value, String[] specialCharArr) {
        boolean validateFlag = false;
        if (value != null && value.trim().length() > 0) {
            for (String symbolStr : specialCharArr) {
                if (value.contains(symbolStr)) {
                    validateFlag = true;
                    break;
                }
            }
        }
        return validateFlag;
    }


    /**
     * 判断字符串长度是否超出
     *
     * @param str
     * @param length
     * @param type
     * @return
     */
    public static boolean strLengthValidate(String str, int length, String type) {

        char[] charsArr = str.toCharArray();
        int strLength = 0;
        for (int i = 0; i < charsArr.length; i++) {
            String temp = String.valueOf(charsArr[i]);
            //判断是否包含中文字符
            if (temp.matches("[\u4e00-\u9fa5]")) {
                strLength += 2;
            } else {
                strLength++;
            }
        }
        Boolean validateFlag = false;
        switch (type) {
            case "gt":
                validateFlag = strLength > length ? true : false;
                break;
            case "ge":
                validateFlag = strLength >= length ? true : false;
                break;
            case "eq":
                validateFlag = strLength == length ? true : false;
                break;
            case "lt":
                validateFlag = strLength < length ? true : false;
                break;
            case "le":
                validateFlag = strLength <= length ? true : false;
                break;
            default:
                validateFlag = false;
                break;
        }
        return validateFlag;
    }

    /**
     * 是否为数字校验
     */
    public static boolean isNumeric(String str) {
        if (StringUtils.isEmpty(str)) {
            return false;
        } else if (StringUtils.isEmpty(str.trim())) {
            return false;
        }
        // 该正则表达式可以匹配所有的数字 包括负数
        Pattern pattern = Pattern.compile("-?[0-9]+(\\.[0-9]+)?");
        String bigStr;
        try {
            bigStr = new BigDecimal(str).toString();
        } catch (Exception e) {
            return false;//异常 说明包含非数字。
        }

        Matcher isNum = pattern.matcher(bigStr); // matcher是全匹配
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }



    /**
     * 是否为数字校验
     */
    public static boolean remainPoint(String str, int length) {
        if (StringUtils.isEmpty(str)) {
            return false;
        } else if (StringUtils.isEmpty(str.trim())) {
            return false;
        }
        String regExp = "-?[0-9]+(\\.[0-9]{1," + length + "})?";
        // 该正则表达式可以匹配所有的数字 包括负数
        Pattern pattern = Pattern.compile(regExp);
        String bigStr;
        try {
            bigStr = new BigDecimal(str).toString();
        } catch (Exception e) {
            return false;//异常 说明包含非数字。
        }

        Matcher isNum = pattern.matcher(bigStr); // matcher是全匹配
        if (!isNum.matches()) {
            return false;
        }
        return true;
    }


}
